/*
 * Copyright 2002-2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.beans.factory.xml;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.parsing.EmptyReaderEventListener;
import org.springframework.beans.factory.parsing.FailFastProblemReporter;
import org.springframework.beans.factory.parsing.NullSourceExtractor;
import org.springframework.beans.factory.parsing.ProblemReporter;
import org.springframework.beans.factory.parsing.ReaderEventListener;
import org.springframework.beans.factory.parsing.SourceExtractor;
import org.springframework.beans.factory.support.AbstractBeanDefinitionReader;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.Constants;
import org.springframework.core.NamedThreadLocal;
import org.springframework.core.io.DescriptiveResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.xml.SimpleSaxErrorHandler;
import org.springframework.util.xml.XmlValidationModeDetector;

/**
 * 用于读取Xml Bean定义的Bean定义读取器.
 * 适用于读取真实的XML文档的BeanDefinitionDocumentReader接口的实现.
 * 通常应用于{@link org.springframework.beans.factory.support.DefaultListableBeanFactory}或者
 * {@link org.springframework.context.support.GenericApplicationContext}内.
 * 这个类通过{@link BeanDefinitionDocumentReader}来加载一个Dom文档,而且当前文档读取器会通过
 * {@link org.springframework.beans.factory.support.BeanDefinitionRegistry}把加载的每一个Bean都注册到给定的工厂内.
 * <p>
 * <p>
 * Bean definition reader for XML bean definitions.
 * Delegates the actual XML document reading to an implementation
 * of the {@link BeanDefinitionDocumentReader} interface.
 * <p>
 * <p>Typically applied to a
 * {@link org.springframework.beans.factory.support.DefaultListableBeanFactory}
 * or a {@link org.springframework.context.support.GenericApplicationContext}.
 * <p>
 * <p>This class loads a DOM document and applies the BeanDefinitionDocumentReader to it.
 * The document reader will register each bean definition with the given bean factory,
 * talking to the latter's implementation of the
 * {@link org.springframework.beans.factory.support.BeanDefinitionRegistry} interface.
 *
 * @author Juergen Hoeller
 * @author Rob Harrop
 * @author Chris Beams
 * @see #setDocumentReaderClass
 * @see BeanDefinitionDocumentReader
 * @see DefaultBeanDefinitionDocumentReader
 * @see BeanDefinitionRegistry
 * @see org.springframework.beans.factory.support.DefaultListableBeanFactory
 * @see org.springframework.context.support.GenericApplicationContext
 * @since 26.11.2003
 */
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {

	/**
	 * 验证禁用开关
	 * Indicates that the validation should be disabled.
	 */
	public static final int VALIDATION_NONE = XmlValidationModeDetector.VALIDATION_NONE;

	/**
	 * 自动检测验证模式
	 * Indicates that the validation mode should be detected automatically.
	 */
	public static final int VALIDATION_AUTO = XmlValidationModeDetector.VALIDATION_AUTO;

	/**
	 * 使用DTD验证
	 * Indicates that DTD validation should be used.
	 */
	public static final int VALIDATION_DTD = XmlValidationModeDetector.VALIDATION_DTD;

	/**
	 * 使用XSD验证
	 * Indicates that XSD validation should be used.
	 */
	public static final int VALIDATION_XSD = XmlValidationModeDetector.VALIDATION_XSD;


	/**
	 * 封装本类的常量
	 * Constants instance for this class
	 */
	private static final Constants constants = new Constants(XmlBeanDefinitionReader.class);
	/**
	 * 验证模式
	 */
	private int validationMode = VALIDATION_AUTO;
	/**
	 * 命名空间支持,为了避免同名XML冲突,引入命名空间功能.
	 */
	private boolean namespaceAware = false;
	/**
	 * 读取文档的类
	 */
	private Class<?> documentReaderClass = DefaultBeanDefinitionDocumentReader.class;
	/**
	 * 问题报告类,快速失败类
	 */
	private ProblemReporter problemReporter = new FailFastProblemReporter();
	/**
	 * 读取事件监听器
	 */
	private ReaderEventListener eventListener = new EmptyReaderEventListener();
	/**
	 * 源元数据扩展器
	 */
	private SourceExtractor sourceExtractor = new NullSourceExtractor();
	/**
	 * 命名空间解析
	 */
	@Nullable
	private NamespaceHandlerResolver namespaceHandlerResolver;
	/**
	 * 文档加载器
	 */
	private DocumentLoader documentLoader = new DefaultDocumentLoader();
	/**
	 * 实体类解析器
	 */
	@Nullable
	private EntityResolver entityResolver;
	/**
	 * 错误处理器
	 */
	private ErrorHandler errorHandler = new SimpleSaxErrorHandler(logger);
	/**
	 * XML验证模式定义处理类
	 */
	private final XmlValidationModeDetector validationModeDetector = new XmlValidationModeDetector();
	/**
	 * 线程安全的保存了当前正在读取的资源文件.
	 */
	private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded =
			new NamedThreadLocal<>("XML bean definition resources currently being loaded");


	/**
	 * 通过给定的Bean工厂创建一个XmlBeanDefinitionReader实例.
	 * <p>
	 * Create new XmlBeanDefinitionReader for the given bean factory.
	 *
	 * @param registry the BeanFactory to load bean definitions into,  通过BeanDefinitionRegistry将Bean定义加载到Bean工厂内.
	 *                 in the form of a BeanDefinitionRegistry
	 */
	public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
		super(registry);
	}


	/**
	 * 是否使用XML验证模式,默认使用.
	 * 如果关闭了验证模式,那么就会开启命名空间的自动感知模式,以便能够正确的处理.
	 * Set whether to use XML validation. Default is {@code true}.
	 * <p>This method switches namespace awareness on if validation is turned off,
	 * in order to still process schema namespaces properly in such a scenario.
	 *
	 * @see #setValidationMode
	 * @see #setNamespaceAware
	 */
	public void setValidating(boolean validating) {
		this.validationMode = (validating ? VALIDATION_AUTO : VALIDATION_NONE);
		this.namespaceAware = !validating;
	}

	/**
	 * 将验证模式设为根据姓名的放那格式,模式是自动匹配的.
	 * Set the validation mode to use by name. Defaults to {@link #VALIDATION_AUTO}.
	 *
	 * @see #setValidationMode
	 */
	public void setValidationModeName(String validationModeName) {
		setValidationMode(constants.asNumber(validationModeName).intValue());
	}

	/**
	 * 指定使用的验证模式,默认使用自动匹配.
	 * 需要注意的是,激活与不激活只限于验证模式本身.如果你关闭了Schema文件验证,那么可能会需要去激活schema的命名空间功能.
	 * Set the validation mode to use. Defaults to {@link #VALIDATION_AUTO}.
	 * <p>Note that this only activates or deactivates validation itself.
	 * If you are switching validation off for schema files, you might need to
	 * activate schema namespace support explicitly: see {@link #setNamespaceAware}.
	 */
	public void setValidationMode(int validationMode) {
		this.validationMode = validationMode;
	}

	/**
	 * 返回正在使用的验证模式
	 * Return the validation mode to use.
	 */
	public int getValidationMode() {
		return this.validationMode;
	}

	/**
	 * 设置是否启用命名空间功能,默认是不启用的.
	 * 在Schema验证启用的时候,通常来说,,不需要用到这个.但是,如果,没有开启验证模式,就需要激活命名空间的功能,为了能够正确的解析文件.
	 * <p>
	 * <p>
	 * Set whether or not the XML parser should be XML namespace aware.
	 * Default is "false".
	 * <p>This is typically not needed when schema validation is active.
	 * However, without validation, this has to be switched to "true"
	 * in order to properly process schema namespaces.
	 */
	public void setNamespaceAware(boolean namespaceAware) {
		this.namespaceAware = namespaceAware;
	}

	/**
	 * 返回是否激活了XML命名空间的功能.
	 * Return whether or not the XML parser should be XML namespace aware.
	 */
	public boolean isNamespaceAware() {
		return this.namespaceAware;
	}

	/**
	 * 指定使用的饿问题报告类(ProblemReporter),默认实现是具有快速失败行为的FailFastProblemReporter类,
	 * 外部工具,可以提供一个替代实现用来处理工具本身的errors报告,和warnings报告.
	 * <p>
	 * <p>
	 * Specify which {@link org.springframework.beans.factory.parsing.ProblemReporter} to use.
	 * <p>The default implementation is {@link org.springframework.beans.factory.parsing.FailFastProblemReporter}
	 * which exhibits fail fast behaviour. External tools can provide an alternative implementation
	 * that collates errors and warnings for display in the tool UI.
	 */
	public void setProblemReporter(@Nullable ProblemReporter problemReporter) {
		this.problemReporter = (problemReporter != null ? problemReporter : new FailFastProblemReporter());
	}

	/**
	 * 指定使用的ReaderEventListener子类.默认实现是一个丢失了所有通知的EmptyReaderEventListener读取时间监听器.
	 * 外部工具,可以提供一个替代实现来监听Bean工厂中组件加载的过程.
	 * <p>
	 * Specify which {@link ReaderEventListener} to use.
	 * <p>The default implementation is EmptyReaderEventListener which discards every event notification.
	 * External tools can provide an alternative implementation to monitor the components being
	 * registered in the BeanFactory.
	 */
	public void setEventListener(@Nullable ReaderEventListener eventListener) {
		this.eventListener = (eventListener != null ? eventListener : new EmptyReaderEventListener());
	}

	/**
	 * 指定使用的SourceExtractor(元数据处理器,用来将元数据加载到bean定义中),默认实现类是一个返回元数据为null的NullSourceExtractor.
	 * 简单来说,就是在运行的时候,没有描述源的元数据添加到Bean配置定义元数据里.
	 * <p>
	 * <p>
	 * Specify the {@link SourceExtractor} to use.
	 * <p>The default implementation is {@link NullSourceExtractor} which simply returns {@code null}
	 * as the source object. This means that - during normal runtime execution -
	 * no additional source metadata is attached to the bean configuration metadata.
	 */
	public void setSourceExtractor(@Nullable SourceExtractor sourceExtractor) {
		this.sourceExtractor = (sourceExtractor != null ? sourceExtractor : new NullSourceExtractor());
	}

	/**
	 * 指定使用的命名空间解析器,如果没有指定的话,通过调用createDefaultNamespaceHandlerResolver()方法创建一个.
	 * <p>
	 * <p>
	 * Specify the {@link NamespaceHandlerResolver} to use.
	 * <p>If none is specified, a default instance will be created through
	 * {@link #createDefaultNamespaceHandlerResolver()}.
	 */
	public void setNamespaceHandlerResolver(@Nullable NamespaceHandlerResolver namespaceHandlerResolver) {
		this.namespaceHandlerResolver = namespaceHandlerResolver;
	}

	/**
	 * 指定使用的DocumentLoader.默认实现是使用JAXP加载文本的DefaultDocumentLoader.
	 * Specify the {@link DocumentLoader} to use.
	 * <p>The default implementation is {@link DefaultDocumentLoader}
	 * which loads {@link Document} instances using JAXP.
	 */
	public void setDocumentLoader(@Nullable DocumentLoader documentLoader) {
		this.documentLoader = (documentLoader != null ? documentLoader : new DefaultDocumentLoader());
	}

	/**
	 * 设置用于解析SAX实体的解析器.
	 * 默认使用ResourceEntityResolver,对于自定义的实体解析方法,用户可以自己重写,比如相对于某些特定的路径.
	 * <p>
	 * <p>
	 * Set a SAX entity resolver to be used for parsing.
	 * <p>By default, {@link ResourceEntityResolver} will be used. Can be overridden
	 * for custom entity resolution, for example relative to some specific base path.
	 */
	public void setEntityResolver(@Nullable EntityResolver entityResolver) {
		this.entityResolver = entityResolver;
	}

	/**
	 * //返回一个实体解析器,如果没有的话,那就创建一个.
	 * Return the EntityResolver to use, building a default resolver
	 * if none specified.
	 */
	protected EntityResolver getEntityResolver() {
		if (this.entityResolver == null) {
			// Determine default EntityResolver to use.
			ResourceLoader resourceLoader = getResourceLoader();
			if (resourceLoader != null) {
				this.entityResolver = new ResourceEntityResolver(resourceLoader);
			} else {
				this.entityResolver = new DelegatingEntityResolver(getBeanClassLoader());
			}
		}
		return this.entityResolver;
	}

	/**
	 * 设置一个错误处理器,来处理XML文件解析中的错误和警告,如果没有设置的话,默认使用SimpleSaxErrorHandler,只是进行一些简单的日志记录,然后
	 * 重新抛出异常,让程序终止允许.
	 * <p>
	 * <p>
	 * Set an implementation of the {@code org.xml.sax.ErrorHandler}
	 * interface for custom handling of XML parsing errors and warnings.
	 * <p>If not set, a default SimpleSaxErrorHandler is used that simply
	 * logs warnings using the logger instance of the view class,
	 * and rethrows errors to discontinue the XML transformation.
	 *
	 * @see SimpleSaxErrorHandler
	 */
	public void setErrorHandler(ErrorHandler errorHandler) {
		this.errorHandler = errorHandler;
	}

	/**
	 * 指定使用的Bean定义文档读取器,负责真正去读取XMLBean定义文档,默认使用{@link DefaultBeanDefinitionDocumentReader}.
	 * <p>
	 * <p>
	 * Specify the {@link BeanDefinitionDocumentReader} implementation to use,
	 * responsible for the actual reading of the XML bean definition document.
	 * <p>The default is {@link DefaultBeanDefinitionDocumentReader}.
	 *
	 * @param documentReaderClass the desired BeanDefinitionDocumentReader implementation class
	 */
	public void setDocumentReaderClass(Class<? extends BeanDefinitionDocumentReader> documentReaderClass) {
		this.documentReaderClass = documentReaderClass;
	}


	/**
	 * 从指定的XML文件中加载Bean定义.
	 * <p>
	 * Load bean definitions from the specified XML file.
	 *
	 * @param resource the resource descriptor for the XML file XML文件的资源描述
	 * @return the number of bean definitions found  找到的Bean定义数量
	 * @throws BeanDefinitionStoreException in case of loading or parsing errors  加载或解析失败时抛出该异常.
	 */
	@Override
	public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
		return loadBeanDefinitions(new EncodedResource(resource));
	}

	/**
	 * 从指定的Xml文件中加载Bean定义.
	 * <p>
	 * Load bean definitions from the specified XML file.
	 *
	 * @param encodedResource the resource descriptor for the XML file,  XML file XML文件的资源描述符,允许指定编码来解析该文件.
	 *                        allowing to specify an encoding to use for parsing the file
	 * @return the number of bean definitions found 找到Bean定义的数量.
	 * @throws BeanDefinitionStoreException in case of loading or parsing errors 加载或解析失败时抛出该异常.
	 */
	public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
		Assert.notNull(encodedResource, "EncodedResource must not be null");
		if (logger.isInfoEnabled()) {
			logger.info("Loading XML bean definitions from " + encodedResource.getResource());
		}

		Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
		if (currentResources == null) {
			//如果是第一次加载,初始化resourcesCurrentlyBeingLoaded
			currentResources = new HashSet<>(4);
			this.resourcesCurrentlyBeingLoaded.set(currentResources);
		}
		if (!currentResources.add(encodedResource)) {
			//如果,添加资源文件失败,抛出异常.
			throw new BeanDefinitionStoreException(
					"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
		}
		//开始读取文件.
		try {
			//获取文件输入流
			InputStream inputStream = encodedResource.getResource().getInputStream();
			try {
				InputSource inputSource = new InputSource(inputStream);
				if (encodedResource.getEncoding() != null) {
					//如果指定了编码格式,则通过指定编码来读取数据流.
					inputSource.setEncoding(encodedResource.getEncoding());
				}
				return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
			} finally {
				//关闭流
				inputStream.close();
			}
		} catch (IOException ex) {
			throw new BeanDefinitionStoreException(
					"IOException parsing XML document from " + encodedResource.getResource(), ex);
		} finally {
			//无论结果如何,一定会移除当前XML文件.
			currentResources.remove(encodedResource);
			//同时,如果当前没有保存任何资源,那么释放掉resourcesCurrentlyBeingLoaded中保存的set.
			if (currentResources.isEmpty()) {
				this.resourcesCurrentlyBeingLoaded.remove();
			}
		}
	}

	/**
	 * 从指定的XML文件中加载Bean定义.
	 * <p>
	 * Load bean definitions from the specified XML file.
	 *
	 * @param inputSource the SAX InputSource to read from 读取源
	 * @return the number of bean definitions found 找到的bean定义数量
	 * @throws BeanDefinitionStoreException in case of loading or parsing errors
	 */
	public int loadBeanDefinitions(InputSource inputSource) throws BeanDefinitionStoreException {
		return loadBeanDefinitions(inputSource, "resource loaded through SAX InputSource");
	}

	/**
	 * 从指定的XML文件中加载Bean定义.
	 * <p>
	 * Load bean definitions from the specified XML file.
	 *
	 * @param inputSource         the SAX InputSource to read from 读取源
	 * @param resourceDescription a description of the resource
	 *                            (can be {@code null} or empty)  当前资源的描述.
	 * @return the number of bean definitions found
	 * @throws BeanDefinitionStoreException in case of loading or parsing errors
	 */
	public int loadBeanDefinitions(InputSource inputSource, @Nullable String resourceDescription)
			throws BeanDefinitionStoreException {

		return doLoadBeanDefinitions(inputSource, new DescriptiveResource(resourceDescription));
	}


	/**
	 * 真正从XML文件中加载bean定义的方法.
	 * Actually load bean definitions from the specified XML file.
	 *
	 * @param inputSource the SAX InputSource to read from
	 * @param resource    the resource descriptor for the XML file
	 * @return the number of bean definitions found
	 * @throws BeanDefinitionStoreException in case of loading or parsing errors
	 * @see #doLoadDocument
	 * @see #registerBeanDefinitions
	 */
	protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {
		try {
			//加载文件,获取dom树.
			Document doc = doLoadDocument(inputSource, resource);
			//通过dom树和资源,注册bean定义.
			return registerBeanDefinitions(doc, resource);
		} catch (BeanDefinitionStoreException ex) {
			throw ex;
		} catch (SAXParseException ex) {
			throw new XmlBeanDefinitionStoreException(resource.getDescription(),
					"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
		} catch (SAXException ex) {
			throw new XmlBeanDefinitionStoreException(resource.getDescription(),
					"XML document from " + resource + " is invalid", ex);
		} catch (ParserConfigurationException ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"Parser configuration exception parsing XML from " + resource, ex);
		} catch (IOException ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"IOException parsing XML document from " + resource, ex);
		} catch (Throwable ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"Unexpected exception parsing XML document from " + resource, ex);
		}
	}

	/**
	 * 使用配置的DocumentLoader加载指定的配置文件.
	 * Actually load the specified document using the configured DocumentLoader.
	 *
	 * @param inputSource the SAX InputSource to read from  输入源
	 * @param resource    the resource descriptor for the XML file  XML文件描述
	 * @return the DOM Document
	 * @throws Exception when thrown from the DocumentLoader
	 * @see #setDocumentLoader
	 * @see DocumentLoader#loadDocument
	 */
	protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
		return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
				getValidationModeForResource(resource), isNamespaceAware());
	}


	/**
	 * 获取指定资源文件对应的验证模式.如果没有明确的配置验证模式.那么就会自动匹配验证模式,如果我们想完全控制验证模式我们可以复写该方法,即时设置了
	 * {@link #VALIDATION_AUTO}.
	 * <p>
	 * <p>
	 * Gets the validation mode for the specified {@link Resource}. If no explicit
	 * validation mode has been configured then the validation mode is
	 * {@link #detectValidationMode detected}.
	 * <p>Override this method if you would like full control over the validation
	 * mode, even when something other than {@link #VALIDATION_AUTO} was set.
	 */
	protected int getValidationModeForResource(Resource resource) {
		//获取当前的指定的验证模式
		int validationModeToUse = getValidationMode();
		if (validationModeToUse != VALIDATION_AUTO) {
			//如果不是自动匹配验证模式,则返回该验证模式.
			return validationModeToUse;
		}
		//尚未指定验证模式,开始根据文件中的声明,确定验证模式.
		//调用的方法可能有三个结果:XSD,DTD,自动匹配.
		int detectedMode = detectValidationMode(resource);
		if (detectedMode != VALIDATION_AUTO) {
			//如果不是自动匹配验证模式,表示,方法中获得了具体的验证模式,所以,不管拉,反正返回去就对了.
			return detectedMode;
		}
		// Hmm, we didn't get a clear indication... Let's assume XSD,
		// since apparently no DTD declaration has been found up until
		// detection stopped (before finding the document's root tag).
		//处理到这,竟然还是自动匹配验证模式,不过,因为没有在整个文件中找到DTD验证模式的标志,所以那就是用XSD验证模式吧.
		return VALIDATION_XSD;
	}

	/**
	 * 根据提供的资源文件猜测出在识别的XML上应该使用的具体的验证
	 * 模式.
	 * 如果文件中包含{@code DOCTYPE},那么就是用DTD验证模式,否则使用XSD验证模式.
	 * 如果想使用自定义解析文件,可以复写该方法.
	 * <p>
	 * <p>
	 * Detects which kind of validation to perform on the XML file identified
	 * by the supplied {@link Resource}. If the file has a {@code DOCTYPE}
	 * definition then DTD validation is used otherwise XSD validation is assumed.
	 * <p>Override this method if you would like to customize resolution
	 * of the {@link #VALIDATION_AUTO} mode.
	 */
	protected int detectValidationMode(Resource resource) {
		//如果文件流已经打开,抛出异常.
		if (resource.isOpen()) {
			throw new BeanDefinitionStoreException(
					"Passed-in Resource [" + resource + "] contains an open stream: " +
							"cannot determine validation mode automatically. Either pass in a Resource " +
							"that is able to create fresh streams, or explicitly specify the validationMode " +
							"on your XmlBeanDefinitionReader instance.");
		}

		InputStream inputStream;
		try {
			inputStream = resource.getInputStream();
		} catch (IOException ex) {
			throw new BeanDefinitionStoreException(
					"Unable to determine validation mode for [" + resource + "]: cannot open InputStream. " +
							"Did you attempt to load directly from a SAX InputSource without specifying the " +
							"validationMode on your XmlBeanDefinitionReader instance?", ex);
		}

		try {
			//调用的方法的默认实现只会有三种结果,XSD验证,DTD验证,自动匹配验证.
			return this.validationModeDetector.detectValidationMode(inputStream);
		} catch (IOException ex) {
			throw new BeanDefinitionStoreException("Unable to determine validation mode for [" +
					resource + "]: an error occurred whilst reading from the InputStream.", ex);
		}
	}

	/**
	 * 创建一个解析类实例,来加载指定Dom文件,获取其中的Bean定义并执行注册操作.
	 * Register the bean definitions contained in the given DOM document.
	 * Called by {@code loadBeanDefinitions}.
	 * <p>Creates a new instance of the parser class and invokes
	 * {@code registerBeanDefinitions} on it.
	 *
	 * @param doc      the DOM document  DOM文件
	 * @param resource the resource descriptor (for context information) 对于文件上下文的描述.
	 * @return the number of bean definitions found  返回获取Bean定义的数量.
	 * @throws BeanDefinitionStoreException in case of parsing errors
	 * @see #loadBeanDefinitions
	 * @see #setDocumentReaderClass
	 * @see BeanDefinitionDocumentReader#registerBeanDefinitions
	 */
	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		//创建Bean定义文本阅读器.`
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		//获取当前Bean定义注册器已经注册过的bean实例的数量.
		int countBefore = getRegistry().getBeanDefinitionCount();
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		//返回本次加载的bean定义实例数量.
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}

	/**
	 * 创建一个真正用于从XML文档中读取Bean定义的BeanDefinitionDocumentReader实例.
	 * 它的默认实现是documentReaderClass.
	 * Create the {@link BeanDefinitionDocumentReader} to use for actually
	 * reading bean definitions from an XML document.
	 * <p>The default implementation instantiates the specified "documentReaderClass".
	 *
	 * @see #setDocumentReaderClass
	 */
	protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
		//创建一个documentReaderClass的实例.
		return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
	}

	/**
	 * Create the {@link XmlReaderContext} to pass over to the document reader.
	 */
	public XmlReaderContext createReaderContext(Resource resource) {
		return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
				this.sourceExtractor, this, getNamespaceHandlerResolver());
	}

	/**
	 * 如果之前没有设置命名空间解析器,那就到调用的时候懒加载一个.
	 * Lazily create a default NamespaceHandlerResolver, if not set before.
	 *
	 * @see #createDefaultNamespaceHandlerResolver()
	 */
	public NamespaceHandlerResolver getNamespaceHandlerResolver() {
		if (this.namespaceHandlerResolver == null) {
			this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();
		}
		return this.namespaceHandlerResolver;
	}

	/**
	 * 如果没有指定的话,创建一个NamespaceHandlerResolver的默认实现类--DefaultNamespaceHandlerResolver.
	 * Create the default implementation of {@link NamespaceHandlerResolver} used if none is specified.
	 * Default implementation returns an instance of {@link DefaultNamespaceHandlerResolver}.
	 */
	protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {
		ClassLoader cl = (getResourceLoader() != null ? getResourceLoader().getClassLoader() : getBeanClassLoader());
		return new DefaultNamespaceHandlerResolver(cl);
	}

}
